﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
using Kimola.Config;

namespace Kimola
{
  internal class APIClient
  {
    internal APIClient()
      : this(null)
    {

    }

    internal APIClient(string apiKey)
    {
      this.apiKey = apiKey;
      this.Query = new Dictionary<string, string>();
    }

    internal string HttpMethod { get; set; }
    internal string Resource { get; set; }
    internal string Parameter { get; set; }
    internal Dictionary<string, string> Query { get; set; }
    internal object Body { get; set; }

    private string apiKey;
    private const string apiUrl = "http://api.kimola.com/search/v1/";
    private const string partSpace = "main";
    private KimolaConfigurationSection Config { get { return (ConfigurationManager.GetSection("kimola") as KimolaConfigurationSection); } }

    internal void Execute()
    {
      this.Execute<object>();
    }

    internal T Execute<T>()
    {
      if (this.Config == null && string.IsNullOrEmpty(this.apiKey))
        throw new ArgumentNullException("apiKey", "You must provide an API Key or use Kimola Configuration Section in web/application configuration file");

      string serviceUrl = string.Format("{0}{1}{2}{3}{4}",
          this.Config == null ? apiUrl : (this.Config.Api.Url.EndsWith("/") ? this.Config.Api.Url : string.Concat(this.Config.Api.Url, "/")),
          this.apiKey ?? this.Config.Api.Key,
          this.Resource == null ? string.Empty : string.Concat("/", this.Resource),
          this.Parameter == null ? string.Empty : string.Concat("/", this.Parameter),
          this.Query == null || this.Query.Count == 0 ? string.Empty : "?" + this.Query.Select(kvp => string.Format("&{0}={1}", kvp.Key, HttpUtility.UrlEncode(kvp.Value))).Aggregate((q1, q2) => q1 + q2));

      JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
      WebResponse webResponse = null;

      KimolaException kimolaException = null;
      Exception exception = null;

      T returnInstance = default(T);

      try
      {
        WebRequest webRequest = WebRequest.Create(serviceUrl);
        webRequest.ContentType = "application/json; charset=utf-8";
        webRequest.Method = this.HttpMethod.ToString();

        if (this.Body != null)
        {
          string json = javaScriptSerializer.Serialize(this.Body);
          byte[] array = Encoding.UTF8.GetBytes(json);

          webRequest.ContentLength = array.Length;
          StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream());
          streamWriter.Write(json);
          streamWriter.Close();
        }

        string responseText = null;

        webResponse = webRequest.GetResponse();
        Stream stream = webResponse.GetResponseStream();
        StreamReader streamReader = new StreamReader(stream);
        responseText = streamReader.ReadToEnd();
        streamReader.Close();
        stream.Close();

        returnInstance = javaScriptSerializer.Deserialize<T>(responseText);
      }
      catch (WebException webException)
      {
        webResponse = webException.Response;
        Stream stream = webResponse.GetResponseStream();
        StreamReader streamReader = new StreamReader(stream);
        string exceptionMessage = streamReader.ReadToEnd();
        streamReader.Close();
        stream.Close();

        kimolaException = new KimolaException(exceptionMessage);
      }
      catch (Exception ex)
      {
        exception = ex;
      }
      finally
      {
        webResponse.Close();
      }

      if (exception != null)
        throw exception;

      if (kimolaException != null)
        throw kimolaException;

      return returnInstance;
    }
  }
}